#ifndef _VECTOR3_H_
#define _VECTOR3_H_
using namespace std;

class Vector3 {
	
public:
	
	// vars
	double x, y, z;
	
	// constructors
	Vector3() {}
	
	Vector3( double theX, double theY, double theZ ) 
    {
		x = theX; y = theY; z = theZ;		
	}
	
	void setXYZ(double theX, double theY, double theZ) 
    {
        x = theX;
        y = theY;
        z = theZ; 
    }
	
	// vector ops
	void normalize() 
    {
		double l = 1.0 / length();
		
		x *= l;
		y *= l;
		z *= l;
	}

    void normalizeXZ()
    {
        float magnitude = sqrt(x*x+z*z);
        if(magnitude > 0)
        {
           x /= magnitude;
           y /= magnitude;
           z /= magnitude;  
        }    
    }

	Vector3 cross( const Vector3 & rhs ) const 
    {
		return( Vector3( y * rhs.z - z * rhs.y, 
		               - x * rhs.z + z * rhs.x,
					     x * rhs.y - y * rhs.x ) );
	}

	double dot( const Vector3 & rhs ) const 
    {
		return( x * rhs.x + y * rhs.y + z * rhs.z );	
	}

	inline double squareLength() const 
    {
		return( x * x + y * y + z * z );
	}
	
	inline double length() const 
    {
		return( sqrt( squareLength() ) );
	}
	
	//  operators
	Vector3 operator + ( const Vector3 & rhs ) const 
    {
		return( Vector3( x + rhs.x, y + rhs.y, z + rhs.z ) );
	}
	
	Vector3 operator - ( const Vector3 & rhs ) const 
    {
		return( Vector3( x - rhs.x, y - rhs.y, z - rhs.z ) );
	}
	
	Vector3 operator / ( double k ) const 
    {
		return( Vector3( x / k, y / k, z / k ) );
	}
	
	Vector3 operator * ( const double k ) const 
    {
		return( Vector3( x * k, y * k, z * k ) );
	}

	Vector3 operator *= ( const double k ) 
    {
		x *= k;
		y *= k;
		z *= k;

		return( *this );
	}

	Vector3 operator /= ( const double k ) 
    {

		x /= k;
		y /= k;
		z /= k;

		return( *this );
	}

	Vector3 operator += ( const Vector3 & rhs ) 
    {
		x += rhs.x;
		y += rhs.y;
		z += rhs.z;

		return( *this );
	}

	Vector3 operator -= ( const Vector3 & rhs ) 
    {
		x -= rhs.x;
		y -= rhs.y;
		z -= rhs.z;

		return( *this );
	}
	
	double & operator [] ( int n ) 
    {
		switch( n ) 
        {	
    		case 0: return( x );
    		case 1: return( y );
    		case 2: return( z );
    		default: ;
			
		}
	}

	friend ostream & operator << ( ostream & o, Vector3 v ) 
    {
		o << "<" << v.x << ", " << v.y << ", " << v.z << ">" << endl;
		return( o );
	}
	
}; 


#endif
